﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;


namespace BizElements.BusinessLayer
{
    /// <summary>
    /// Provides common value parsing functionalities.
    /// </summary>
    public static class NumberParser
    {
        #region ParseInt.

        /// <summary>
        /// Converts the string representation of a number to its 32-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static int? ParseInt(string textRepresentation)
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            textRepresentation = textRepresentation.Trim();
            int number;
            bool isParsed = int.TryParse(textRepresentation, out number);
            return (isParsed) ? (int?)number : null;
        }

        /// <summary>
        /// Converts the string representation of a number to its 32-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static int? ParseInt(string textRepresentation, IMessageFormatter formatter)
        {
            return ParseInt(textRepresentation, formatter.IntStyle, formatter.IntProvider);
        }

        /// <summary>
        /// Converts the string representation of a number to its 32-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static int? ParseInt(string textRepresentation, IFormatProvider provider)
        {
            return ParseInt(textRepresentation, NumberStyles.Integer, provider);
        }

        /// <summary>
        /// Converts the string representation of a number to its 32-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values 
        /// that indicates the permitted format of textRepresentation. A typical value to specify is 
        /// <see cref="System.Globalization.NumberStyles.Integer"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static int? ParseInt(string textRepresentation, NumberStyles style, IFormatProvider provider)
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            textRepresentation = textRepresentation.Trim();
            int number;
            bool isParsed = int.TryParse(textRepresentation, style, provider, out number);
            return (isParsed) ? (int?)number : null;
        }

        #endregion

        #region ParseLong.

        /// <summary>
        /// Converts the string representation of a number to its 64-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static long? ParseLong(string textRepresentation)
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            textRepresentation = textRepresentation.Trim();
            long number;
            bool isParsed = long.TryParse(textRepresentation, out number);
            return (isParsed) ? (long?)number : null;
        }

        /// <summary>
        /// Converts the string representation of a number to its 64-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static long? ParseLong(string textRepresentation, IMessageFormatter formatter)
        {
            return ParseLong(textRepresentation, formatter.IntStyle, formatter.IntProvider);
        }

        /// <summary>
        /// Converts the string representation of a number to its 64-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static long? ParseLong(string textRepresentation, IFormatProvider provider)
        {
            return ParseLong(textRepresentation, NumberStyles.Integer, provider);
        }

        /// <summary>
        /// Converts the string representation of a number to its 64-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values 
        /// that indicates the permitted format of textRepresentation. A typical value to specify is 
        /// <see cref="System.Globalization.NumberStyles.Integer"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static long? ParseLong(string textRepresentation, NumberStyles style, IFormatProvider provider)
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            textRepresentation = textRepresentation.Trim();
            long number;
            bool isParsed = long.TryParse(textRepresentation, style, provider, out number);
            return (isParsed) ? (long?)number : null;
        }

        #endregion

        #region ParseFloat.

        /// <summary>
        /// Converts the string representation of a number to its single-precision floating point number equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static float? ParseFloat(string textRepresentation, IMessageFormatter formatter)
        {
            return ParseFloat(textRepresentation, formatter.RealStyle, formatter.RealProvider);
        }

        /// <summary>
        /// Converts the string representation of a number to its single-precision floating point number equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static float? ParseFloat(string textRepresentation, IFormatProvider provider)
        {
            return ParseFloat(textRepresentation, NumberStyles.Float | NumberStyles.AllowThousands, provider);
        }

        /// <summary>
        /// Converts the string representation of a number to its single-precision floating point number equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values 
        /// that indicates the permitted format of textRepresentation. A typical value to specify is 
        /// <see cref="System.Globalization.NumberStyles.Float"/> combined with <see cref="System.Globalization.NumberStyles.AllowThousands"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static float? ParseFloat(string textRepresentation, NumberStyles style, IFormatProvider provider)
        {
            float number;
            bool isParsed = float.TryParse(textRepresentation, style, provider, out number);
            return (isParsed) ? (float?)number : null;
        }

        #endregion

        #region ParseDouble.

        /// <summary>
        /// Converts the string representation of a number to its double-precision floating point number equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static double? ParseDouble(string textRepresentation, IMessageFormatter formatter)
        {
            return ParseDouble(textRepresentation, formatter.RealStyle, formatter.RealProvider);
        }

        /// <summary>
        /// Converts the string representation of a number to its double-precision floating point number equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static double? ParseDouble(string textRepresentation, IFormatProvider provider)
        {
            return ParseDouble(textRepresentation, NumberStyles.Float | NumberStyles.AllowThousands, provider);
        }

        /// <summary>
        /// Converts the string representation of a number to its double-precision floating point number equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values 
        /// that indicates the permitted format of textRepresentation. A typical value to specify is 
        /// <see cref="System.Globalization.NumberStyles.Float"/> combined with <see cref="System.Globalization.NumberStyles.AllowThousands"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static double? ParseDouble(string textRepresentation, NumberStyles style, IFormatProvider provider)
        {
            double number;
            bool isParsed = double.TryParse(textRepresentation, style, provider, out number);
            return (isParsed) ? (double?)number : null;
        }

        #endregion

        #region ParseDecimal.

        /// <summary>
        /// Converts the string representation of a number to its <b>Decimal</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static decimal? ParseDecimal(string textRepresentation, IMessageFormatter formatter)
        {
            return ParseDecimal(textRepresentation, formatter.RealStyle, formatter.RealProvider);
        }

        /// <summary>
        /// Converts the string representation of a number to its <b>Decimal</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static decimal? ParseDecimal(string textRepresentation, IFormatProvider provider)
        {
            return ParseDecimal(textRepresentation, NumberStyles.Number, provider);
        }

        /// <summary>
        /// Converts the string representation of a number to its <b>Decimal</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values 
        /// that indicates the permitted format of textRepresentation. A typical value to specify is 
        /// <see cref="System.Globalization.NumberStyles.Number"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static decimal? ParseDecimal(string textRepresentation, NumberStyles style, IFormatProvider provider)
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            textRepresentation = textRepresentation.Trim();
            decimal number;
            bool isParsed = decimal.TryParse(textRepresentation, style, provider, out number);
            return (isParsed) ? (decimal?)number : null;
        }

        #endregion

        #region IsInteger.

        /// <summary>
        /// Checks whether the given string represents an integer value.
        /// </summary>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsInteger(string str)
        {
            long? integer = ParseLong(str);
            return integer.HasValue;
        }

        /// <summary>
        /// Checks whether the given string represents an integer value.
        /// </summary>
        /// <param name="str">A string to test.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsInteger(string str, IMessageFormatter formatter)
        {
            long? integer = ParseLong(str, formatter);
            return integer.HasValue;
        }

        /// <summary>
        /// Checks whether the given string represents an integer value.
        /// </summary>
        /// <param name="str">A string to test.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>str</b>.</param>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsInteger(string str, IFormatProvider provider)
        {
            long? integer = ParseLong(str, provider);
            return integer.HasValue;
        }

        /// <summary>
        /// Checks whether the given string represents an integer value.
        /// </summary>
        /// <param name="str">A string to test.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values 
        /// that indicates the permitted format of textRepresentation. A typical value to specify is 
        /// <see cref="System.Globalization.NumberStyles.Integer"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsInteger(string str, NumberStyles style, IFormatProvider provider)
        {
            long? integer = ParseLong(str, style, provider);
            return integer.HasValue;
        }

        #endregion

        #region IsNumber.

        /// <summary>
        /// Checks whether the given string represents a number.
        /// </summary>
        /// <param name="str">A string to test.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsNumber(string str, IMessageFormatter formatter)
        {
            double? number = ParseDouble(str, formatter.RealProvider);
            return number.HasValue;
        }

        /// <summary>
        /// Checks whether the given string represents a number.
        /// </summary>
        /// <param name="str">A string to test.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>str</b>.</param>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsNumber(string str, IFormatProvider provider)
        {
            double? number = ParseDouble(str, provider);
            return number.HasValue;
        }

        /// <summary>
        /// Checks whether the given string represents a number.
        /// </summary>
        /// <param name="str">A string to test.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values 
        /// that indicates the permitted format of textRepresentation. A typical value to specify is 
        /// <see cref="System.Globalization.NumberStyles.Number"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>str</b>.</param>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsNumber(string str, NumberStyles style, IFormatProvider provider)
        {
            double? number = ParseDouble(str, style, provider);
            return number.HasValue;
        }

        #endregion

        #region ParseEnum.

        /// <summary>
        /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
        /// </summary>
        /// <typeparam name="T">The <see cref="Type"/> of the enumeration.</typeparam>
        /// <param name="textRepresentation">A string containing the name or value to convert.</param>
        /// <returns>An object of type enumType whose value is represented by value. <b>null</b> if conversion fails.</returns>
        public static T? ParseEnum<T>(string textRepresentation) where T : struct
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            try { return (T)Enum.Parse(typeof(T), textRepresentation); }
            catch { return null; }
        }

        /// <summary>
        /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
        /// </summary>
        /// <typeparam name="T">The <see cref="Type"/> of the enumeration.</typeparam>
        /// <param name="textRepresentation">A string containing the name or value to convert.</param>
        /// <param name="ignoreCase">If <b>true</b>, ignore case; otherwise, regard case.</param>
        /// <returns>An object of type enumType whose value is represented by value. <b>null</b> if conversion fails.</returns>
        public static T? ParseEnum<T>(string textRepresentation, bool ignoreCase) where T : struct
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            try { return (T)Enum.Parse(typeof(T), textRepresentation, ignoreCase); }
            catch { return null; }
        }

        private static object ParseEnum(Type enumType, string textRepresentation, bool ignoreCase)
        {
            try { return Enum.Parse(enumType, textRepresentation, ignoreCase); }
            catch { return null; }
        }

        #endregion

        #region ParseDateTime.

        /// <summary>
        /// Converts the string representation of a date to its <b>DateTime</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a date to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A date if conversion succeeded; <b>null</b> otherwise.</returns>
        public static DateTime? ParseDateTime(string textRepresentation, IMessageFormatter formatter)
        {
            return ParseDateTime(textRepresentation, formatter.DateStyle, formatter.DateProvider, formatter.DateFormat);
        }

        /// <summary>
        /// Converts the string representation of a date to its <b>DateTime</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a date to convert.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A date if conversion succeeded; <b>null</b> otherwise.</returns>
        public static DateTime? ParseDateTime(string textRepresentation, IFormatProvider provider)
        {
            return ParseDateTime(textRepresentation, DateTimeStyles.None, provider, null);
        }

        /// <summary>
        /// Converts the string representation of a date to its <b>DateTime</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a date to convert.</param>
        /// <param name="styles">A bitwise combination of <see cref="System.Globalization.DateTimeStyles"/> 
        /// values that indicates the permitted format of textRepresentation. A typical value to specify is 
        /// <see cref="System.Globalization.DateTimeStyles.None"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A date if conversion succeeded; <b>null</b> otherwise.</returns>
        public static DateTime? ParseDateTime(string textRepresentation, DateTimeStyles styles, IFormatProvider provider)
        {
            return ParseDateTime(textRepresentation, styles, provider, null);
        }

        /// <summary>
        /// Converts the string representation of a date to its <b>DateTime</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a date to convert.</param>
        /// <param name="styles">A bitwise combination of <see cref="System.Globalization.DateTimeStyles"/> 
        /// values that indicates the permitted format of textRepresentation. A typical value to specify is 
        /// <see cref="System.Globalization.DateTimeStyles.None"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific 
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <param name="format">The expected format of <b>textRepresentation</b>.</param>
        /// <returns>A date if conversion succeeded; <b>null</b> otherwise.</returns>
        public static DateTime? ParseDateTime(string textRepresentation, DateTimeStyles styles, IFormatProvider provider, string format)
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            textRepresentation = textRepresentation.Trim();
            DateTime date;
            bool isParsed;
            if (format != null)
            {
                isParsed = DateTime.TryParseExact(textRepresentation, format, provider, styles, out date);

                // Retry without exact format.
                if (!isParsed)
                    isParsed = DateTime.TryParse(textRepresentation, provider, styles, out date);
            }
            else
            {
                isParsed = DateTime.TryParse(textRepresentation, provider, styles, out date);
            }

            return (isParsed) ? (DateTime?)date : null;
        }

        #endregion

        #region ParseValue.

        /// <summary>
        /// Converts the string to a value of the specified type.
        /// </summary>
        /// <param name="valueType">Type of the value to return.</param>
        /// <param name="textRepresentation">A string containing a value to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A value if conversion succeeded; <b>null</b> otherwise.</returns>
        public static object ParseValue(Type valueType, string textRepresentation, IMessageFormatter formatter)
        {
            if (valueType == null) throw new ArgumentNullException("valueType", "Type of the value must be specified.");
            if (formatter == null) throw new ArgumentNullException("formatter", "Formatter must be provided.");

            if (string.IsNullOrEmpty(textRepresentation))
                return null;
            textRepresentation = textRepresentation.Trim();
            if (textRepresentation.Length == 0)
                return null;

            object hiByteCountTypeValue = null;
            if (TypeUtil.IsText(valueType))
                hiByteCountTypeValue = textRepresentation;
            else if (TypeUtil.IsInteger(valueType))
                hiByteCountTypeValue = ParseLong(textRepresentation);
            else if (TypeUtil.IsFloatingPointNumber(valueType))
                hiByteCountTypeValue = ParseDecimal(textRepresentation, formatter);
            else if (TypeUtil.IsDate(valueType))
                hiByteCountTypeValue = ParseDateTime(textRepresentation, formatter);
            else if (valueType.IsEnum)
                hiByteCountTypeValue = ParseEnum(valueType, textRepresentation, true);
            else
                throw new ArgumentException("Data type not supported: " + valueType.FullName);

            // Downgrade to the requested type.
            object requestedTypeValue;
            if (hiByteCountTypeValue != null)
                requestedTypeValue = Convert.ChangeType(hiByteCountTypeValue, valueType);
            else
                requestedTypeValue = null;

            return requestedTypeValue;
        }

        /// <summary>
        /// Converts the string to a value of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of the value to return.</typeparam>
        /// <param name="textRepresentation">A string containing a value to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A value if conversion succeeded; <b>null</b> otherwise.</returns>
        public static Nullable<T> ParseValue<T>(string textRepresentation, IMessageFormatter formatter)
            where T : struct, IConvertible
        {
            object value = ParseValue(typeof(T), textRepresentation, formatter);
            if (value != null)
                return (T)value;
            else
                return null;
        }

        #endregion

        #region ParseArray.

        /// <summary>
        /// Converts the string to an array of values of the specified type.
        /// </summary>
        /// <param name="elementType">Type of the value to return.</param>
        /// <param name="delimitedElements">A string containing values to convert.</param>
        /// <param name="delimiter">A character which delimites the elements of the array in the string.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Array which contains the objects of the specified type and nulls for values which couldn't be parsed.</returns>
        public static object[] ParseArray(Type elementType, string delimitedElements, char delimiter, IMessageFormatter formatter)
        {
            string[] txtElements = delimitedElements.Split(delimiter);
            object[] arr = new object[txtElements.Length];
            for (int idxElement = 0; idxElement < arr.Length; idxElement++)
                arr[idxElement] = ParseValue(elementType, txtElements[idxElement], formatter);

            return arr;
        }

        /// <summary>
        /// Converts the string to an array of values of the specified type.
        /// </summary>
        /// <param name="elementType">Type of the value to return.</param>
        /// <param name="delimitedElements">A string containing values to convert.</param>
        /// <param name="delimiter">A string which delimites the elements of the array in the string.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Array which contains the objects of the specified type and nulls for values which couldn't be parsed.</returns>
        public static object[] ParseArray(Type elementType, string delimitedElements, string delimiter, IMessageFormatter formatter)
        {
            string[] txtElements = delimitedElements.Split(new string[] { delimiter }, StringSplitOptions.None);
            object[] arr = new object[txtElements.Length];
            for (int idxElement = 0; idxElement < arr.Length; idxElement++)
                arr[idxElement] = ParseValue(elementType, txtElements[idxElement], formatter);

            return arr;
        }

        /// <summary>
        /// Converts the string to an array of values of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of the value to return.</typeparam>
        /// <param name="delimitedElements">A string containing values to convert.</param>
        /// <param name="delimiter">A character which delimites the elements of the array in the string.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Array which contains the objects of the specified type and nulls for values which couldn't be parsed.</returns>
        public static Nullable<T>[] ParseArray<T>(string delimitedElements, char delimiter, IMessageFormatter formatter)
            where T : struct, IConvertible
        {
            object[] arr = ParseArray(typeof(T), delimitedElements, delimiter, formatter);
            T?[] strongTypedArray = new T?[arr.Length];
            arr.CopyTo(strongTypedArray, 0);
            return strongTypedArray;
        }

        /// <summary>
        /// Converts the string to an array of values of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of the value to return.</typeparam>
        /// <param name="delimitedElements">A string containing values to convert.</param>
        /// <param name="delimiter">A character which delimites the elements of the array in the string.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Array which contains the objects of the specified type and nulls for values which couldn't be parsed.</returns>
        public static Nullable<T>[] ParseArray<T>(string delimitedElements, string delimiter, IMessageFormatter formatter)
            where T : struct, IConvertible
        {
            object[] arr = ParseArray(typeof(T), delimitedElements, delimiter, formatter);
            T?[] strongTypedArray = new T?[arr.Length];
            arr.CopyTo(strongTypedArray, 0);
            return strongTypedArray;
        }

        #endregion

        #region ParseDictionary.

        /// <summary>
        /// Converts a string to a dictionary with keys and values of the specified types.
        /// </summary>
        /// <param name="keyType">The type of the keys in the dictionary.</param>
        /// <param name="valueType">The type of the values in the dictionary.</param>
        /// <param name="delimitedVariables">A string containing varibles (key-value pairs) to convert.</param>
        /// <param name="variableDelimiter">A character which delimites variables in the string.</param>
        /// <param name="keyValueDelimiter">A character which delimites a key from a value in a key-value pair.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Hashtable which contains the keys and values of the specified types. 
        /// Values which couldn't be parsed are represented with <b>null</b> references.</returns>
        public static Hashtable ParseDictionary(Type keyType, Type valueType, string delimitedVariables, char variableDelimiter, char keyValueDelimiter, IMessageFormatter formatter)
        {
            string[] keyValuePairs = delimitedVariables.Split(new char[] { variableDelimiter }, StringSplitOptions.RemoveEmptyEntries);
            Hashtable dictionary = new Hashtable(keyValuePairs.Length);
            foreach (string keyAndValue in keyValuePairs)
            {
                if (string.IsNullOrWhiteSpace(keyAndValue))
                    continue;

                int firstDelimiterOccurrence = keyAndValue.IndexOf(keyValueDelimiter);
                if (firstDelimiterOccurrence < 0)
                    throw new InvalidOperationException("Key-value pair (" + keyAndValue + ") doesn't contain the specified key-value delimiter (" + keyValueDelimiter + ").");

                int keyLen = firstDelimiterOccurrence;
                string keyString = keyAndValue.Substring(0, keyLen);

                const int delimiterLen = 1;
                int valueStart = firstDelimiterOccurrence + delimiterLen;
                string valueString = (valueStart < keyAndValue.Length) ? keyAndValue.Substring(valueStart, keyAndValue.Length - valueStart) : string.Empty;

                object key = ParseValue(keyType, keyString, formatter);
                object value = ParseValue(valueType, valueString, formatter);

                dictionary[key] = value;
            }

            return dictionary;
        }

        /// <summary>
        /// Converts a string to a dictionary with keys and values of the specified types.
        /// </summary>
        /// <param name="keyType">The type of the keys in the dictionary.</param>
        /// <param name="valueType">The type of the values in the dictionary.</param>
        /// <param name="delimitedVariables">A string containing varibles (key-value pairs) to convert.</param>
        /// <param name="variableDelimiter">A string which delimites variables in the string.</param>
        /// <param name="keyValueDelimiter">A string which delimites a key from a value in a key-value pair.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Hashtable which contains the keys and values of the specified types. 
        /// Values which couldn't be parsed are represented with <b>null</b> references.</returns>
        public static Hashtable ParseDictionary(Type keyType, Type valueType, string delimitedVariables, string variableDelimiter, string keyValueDelimiter, IMessageFormatter formatter)
        {
            string[] keyValuePairs = delimitedVariables.Split(new string[] { variableDelimiter }, StringSplitOptions.None);
            Hashtable dictionary = new Hashtable(keyValuePairs.Length);
            foreach (string keyAndValue in keyValuePairs)
            {
                if (string.IsNullOrWhiteSpace(keyAndValue))
                    continue;

                int firstDelimiterOccurrence = keyAndValue.IndexOf(keyValueDelimiter);
                if (firstDelimiterOccurrence < 0)
                    throw new InvalidOperationException("Key-value pair (" + keyAndValue + ") doesn't contain the specified key-value delimiter (" + keyValueDelimiter + ").");

                int keyLen = firstDelimiterOccurrence;
                string keyString = keyAndValue.Substring(0, keyLen);

                int delimiterLen = keyValueDelimiter.Length;
                int valueStart = firstDelimiterOccurrence + delimiterLen;
                string valueString = (valueStart < keyAndValue.Length) ? keyAndValue.Substring(valueStart, keyAndValue.Length - valueStart) : string.Empty;

                object key = ParseValue(keyType, keyString, formatter);
                object value = ParseValue(valueType, valueString, formatter);

                dictionary[key] = value;
            }

            return dictionary;
        }

        /// <summary>
        /// Converts a string to a dictionary with keys and values of the specified types.
        /// </summary>
        /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
        /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
        /// <param name="delimitedVariables">A string containing varibles (key-value pairs) to convert.</param>
        /// <param name="variableDelimiter">A character which delimites variables in the string.</param>
        /// <param name="keyValueDelimiter">A character which delimites a key from a value in a key-value pair.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Dictionary which contains the keys and values of the specified types. 
        /// Values which couldn't be parsed are represented with <b>null</b> references.</returns>
        public static Dictionary<TKey, Nullable<TValue>> ParseDictionary<TKey, TValue>(string delimitedVariables, char variableDelimiter, char keyValueDelimiter, IMessageFormatter formatter)
            where TValue : struct, IConvertible
        {
            Hashtable table = ParseDictionary(typeof(TKey), typeof(TValue), delimitedVariables, variableDelimiter, keyValueDelimiter, formatter);
            Dictionary<TKey, TValue?> strongTypedDictionary = new Dictionary<TKey, TValue?>(table.Count);
            foreach (DictionaryEntry keyAndValue in table)
            {
                TKey key = (TKey)keyAndValue.Key;
                TValue? value;
                if (keyAndValue.Value != null)
                    value = (TValue)keyAndValue.Value;
                else
                    value = null;

                strongTypedDictionary[key] = value;
            }

            return strongTypedDictionary;
        }

        /// <summary>
        /// Converts a string to a dictionary with keys and values of the specified types.
        /// </summary>
        /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
        /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
        /// <param name="delimitedVariables">A string containing varibles (key-value pairs) to convert.</param>
        /// <param name="variableDelimiter">A string which delimites variables in the string.</param>
        /// <param name="keyValueDelimiter">A string which delimites a key from a value in a key-value pair.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Dictionary which contains the keys and values of the specified types. 
        /// Values which couldn't be parsed are represented with <b>null</b> references.</returns>
        public static Dictionary<TKey, Nullable<TValue>> ParseDictionary<TKey, TValue>(string delimitedVariables, string variableDelimiter, string keyValueDelimiter, IMessageFormatter formatter)
            where TValue : struct, IConvertible
        {
            Hashtable table = ParseDictionary(typeof(TKey), typeof(TValue), delimitedVariables, variableDelimiter, keyValueDelimiter, formatter);
            Dictionary<TKey, TValue?> strongTypedDictionary = new Dictionary<TKey, TValue?>(table.Count);
            foreach (DictionaryEntry keyAndValue in table)
            {
                TKey key = (TKey)keyAndValue.Key;
                TValue? value;
                if (keyAndValue.Value != null)
                    value = (TValue)keyAndValue.Value;
                else
                    value = null;

                strongTypedDictionary[key] = value;
            }

            return strongTypedDictionary;
        }

        #endregion

        #region ParseValidValues.

        /// <summary>
        /// Converts the string to an array of values of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of the value to return.</typeparam>
        /// <param name="delimitedElements">A string containing values to convert.</param>
        /// <param name="delimiter">A character which delimites the elements of the array in the string.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Array which contains only values which were succesfully parsed.</returns>
        public static T[] ParseValidValues<T>(string delimitedElements, char delimiter, IMessageFormatter formatter)
            where T : struct, IConvertible
        {
            T?[] nullableValues = ParseArray<T>(delimitedElements, delimiter, formatter);
            return GetElementsWithValues<T>(nullableValues);
        }

        /// <summary>
        /// Converts the string to an array of values of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of the value to return.</typeparam>
        /// <param name="delimitedElements">A string containing values to convert.</param>
        /// <param name="delimiter">A character which delimites the elements of the array in the string.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and 
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Array which contains only values which were succesfully parsed.</returns>
        public static T[] ParseValidValues<T>(string delimitedElements, string delimiter, IMessageFormatter formatter)
            where T : struct, IConvertible
        {
            T?[] nullableValues = ParseArray<T>(delimitedElements, delimiter, formatter);
            return GetElementsWithValues<T>(nullableValues);
        }

        private static T[] GetElementsWithValues<T>(T?[] nullableValues)
            where T : struct
        {
            List<T> values = new List<T>();
            foreach (T? val in nullableValues)
            {
                if (val.HasValue)
                    values.Add(val.Value);
            }

            return values.ToArray();
        }

        #endregion

        #region ParseBool.

        /// <summary>
        /// Converts the specified string representation of a logical value to its Boolean equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <returns>A boolean value if conversion succeeded; <b>null</b> otherwise.</returns>
        public static bool? ParseBool(string textRepresentation)
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            textRepresentation = textRepresentation.Trim();
            bool val;
            bool isParsed = bool.TryParse(textRepresentation, out val);
            return (isParsed) ? (bool?)val : null;
        }

        /// <summary>
        /// Checks whether the given string represents a logical true value.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <returns><b>true</b> if the string represents a logical true value, <b>null</b> otherwise.</returns>
        public static bool IsTrue(string textRepresentation)
        {
            bool? val = ParseBool(textRepresentation);
            bool notNullAndTrue = (val.HasValue && val.Value);
            return notNullAndTrue;
        }

        #endregion
    }
}